<html>

<head>
<meta charset="utf-8"/>
<meta name="description" content="Explore Perlin Noise in real time."/>
<link rel="stylesheet" href="style.css"/>
<title>NoiseGL</title>

<meta name="title" content="NoiseGL"/>
<meta name="description"
        content="Explore Perlin Noise in real time. Customize several parameters."/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no"/>
<meta name="keywords" content="indie, math, real time, noise, perlin, webgl, shader"/>
<meta name="url" content="https://cook1eegames.feedia.co/NoiseGL"/>
<meta name="og:title" content="NoiseGL"/>
<meta name="og:type" content="website"/>
<meta name="og:url" content="https://cook1eegames.feedia.co/NoiseGL"/>
<meta name="og:description"
        content="Explore Perlin Noise in real time. Customize several parameters."/>
<meta name="og:image" content="https://cook1eegames.feedia.co/Images/Previews/noisegl.png"/>
<meta name="twitter:card" content="summary_large_image"/>
<meta name="twitter:title" content="NoiseGL"/>
<meta name="twitter:description"
        content="Explore Perlin Noise in real time. Customize several parameters."/>
<meta name="twitter:image" content="https://cook1eegames.feedia.co/Images/Previews/noisegl.png"/>
<meta name="twitter:site" content="@cook1eegames"/>
<meta name="twitter:creator" content="@cook1eegames"/>
</head>

<body style="margin: 0">

<canvas id="cnv" width="1024" height="576"></canvas>

<div id="app">
    <div class="toolbar">
        <table>
            <tr>
                <td style="width: 25%;">
                    <h3>Info</h3>
                    <p>Zoom: {{formatNumber(1 / camRange)}}x</p>
                    <p>Position: ({{formatNumber(camPos[0])}}, {{formatNumber(camPos[1])}})</p>
                    <p>Time Elapsed: {{formatTime(time)}}</p>
                    <p>FPS: {{formatNumber(fps)}}</p>
                </td>
                <td>
                    <h3>Main Settings</h3>
                    <label>Color Speed
                        <input type="range" min="0.1" max="10" step="0.001" v-model="colorSpeed" v-on:input="setColorSpeed(colorSpeed)"/>
                        <input type="number" min="0" max="100" step="0.1" v-model="colorSpeed" v-on:input="setColorSpeed(colorSpeed)"/>
                        </label><br/>
                    <label>Timescale
                        <input type="range" min="0" max="10" step="0.001" v-model="timeScale"/> 
                        <input type="number" min="-100" max="100" step="0.1" v-model="timeScale"/>
                    </label><br/>
                    <button v-on:click="time = 0">Restart Simulation</button>
                </td>
                <td>
                    <h3>Color Scheme</h3>
                    <button v-for="(s, i) in colorSchemes" v-on:click="setColorScheme(i)">{{s}}</button>
                </td>
                <td>
                    <h3>Formula</h3>
                    <button v-for="(f, i) in formulaTypes" v-on:click="setFormulaType(i)">{{f}}</button>
                </td>
                <td>
                    <h1>Help</h1>
                    <p>Drag to look around, Mouse Wheel to zoom. <a href="https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83">Noise Code by Stefan Gustavson</a></p>
                </td>
            </tr>
        </table><br/>
    </div>
</div>

<script id="vertexshader" type="x-shader/x-vertex">
#version 100

attribute vec2 coordinates;

void main()
{
    gl_Position = vec4(coordinates, 0.0, 1.0);
}
</script>

<script id="fragmentshader" type="x-shader/x-fragment">
#version 100
precision mediump float;

uniform vec2 resolution;

uniform vec2 camPos;
uniform float camRange;

uniform float time;
uniform float colorSpeed;
uniform int colorScheme;

uniform int formulaType;

//	Classic Perlin 3D Noise 
//	by Stefan Gustavson
//
vec4 permute(vec4 x){return mod(((x*34.0)+1.0)*x, 289.0);}
vec4 taylorInvSqrt(vec4 r){return 1.79284291400159 - 0.85373472095314 * r;}
vec3 fade(vec3 t) {return t*t*t*(t*(t*6.0-15.0)+10.0);}

float cnoise(vec3 P){
  vec3 Pi0 = floor(P); // Integer part for indexing
  vec3 Pi1 = Pi0 + vec3(1.0); // Integer part + 1
  Pi0 = mod(Pi0, 289.0);
  Pi1 = mod(Pi1, 289.0);
  vec3 Pf0 = fract(P); // Fractional part for interpolation
  vec3 Pf1 = Pf0 - vec3(1.0); // Fractional part - 1.0
  vec4 ix = vec4(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
  vec4 iy = vec4(Pi0.yy, Pi1.yy);
  vec4 iz0 = Pi0.zzzz;
  vec4 iz1 = Pi1.zzzz;

  vec4 ixy = permute(permute(ix) + iy);
  vec4 ixy0 = permute(ixy + iz0);
  vec4 ixy1 = permute(ixy + iz1);

  vec4 gx0 = ixy0 / 7.0;
  vec4 gy0 = fract(floor(gx0) / 7.0) - 0.5;
  gx0 = fract(gx0);
  vec4 gz0 = vec4(0.5) - abs(gx0) - abs(gy0);
  vec4 sz0 = step(gz0, vec4(0.0));
  gx0 -= sz0 * (step(0.0, gx0) - 0.5);
  gy0 -= sz0 * (step(0.0, gy0) - 0.5);

  vec4 gx1 = ixy1 / 7.0;
  vec4 gy1 = fract(floor(gx1) / 7.0) - 0.5;
  gx1 = fract(gx1);
  vec4 gz1 = vec4(0.5) - abs(gx1) - abs(gy1);
  vec4 sz1 = step(gz1, vec4(0.0));
  gx1 -= sz1 * (step(0.0, gx1) - 0.5);
  gy1 -= sz1 * (step(0.0, gy1) - 0.5);

  vec3 g000 = vec3(gx0.x,gy0.x,gz0.x);
  vec3 g100 = vec3(gx0.y,gy0.y,gz0.y);
  vec3 g010 = vec3(gx0.z,gy0.z,gz0.z);
  vec3 g110 = vec3(gx0.w,gy0.w,gz0.w);
  vec3 g001 = vec3(gx1.x,gy1.x,gz1.x);
  vec3 g101 = vec3(gx1.y,gy1.y,gz1.y);
  vec3 g011 = vec3(gx1.z,gy1.z,gz1.z);
  vec3 g111 = vec3(gx1.w,gy1.w,gz1.w);

  vec4 norm0 = taylorInvSqrt(vec4(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
  g000 *= norm0.x;
  g010 *= norm0.y;
  g100 *= norm0.z;
  g110 *= norm0.w;
  vec4 norm1 = taylorInvSqrt(vec4(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
  g001 *= norm1.x;
  g011 *= norm1.y;
  g101 *= norm1.z;
  g111 *= norm1.w;

  float n000 = dot(g000, Pf0);
  float n100 = dot(g100, vec3(Pf1.x, Pf0.yz));
  float n010 = dot(g010, vec3(Pf0.x, Pf1.y, Pf0.z));
  float n110 = dot(g110, vec3(Pf1.xy, Pf0.z));
  float n001 = dot(g001, vec3(Pf0.xy, Pf1.z));
  float n101 = dot(g101, vec3(Pf1.x, Pf0.y, Pf1.z));
  float n011 = dot(g011, vec3(Pf0.x, Pf1.yz));
  float n111 = dot(g111, Pf1);

  vec3 fade_xyz = fade(Pf0);
  vec4 n_z = mix(vec4(n000, n100, n010, n110), vec4(n001, n101, n011, n111), fade_xyz.z);
  vec2 n_yz = mix(n_z.xy, n_z.zw, fade_xyz.y);
  float n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); 
  return 2.2 * n_xyz;
}

float noiseFromFormula(vec2 coord, int type)
{
    if(type == 0)
    {
        return cnoise(vec3(coord, time));
    }
    if(type == 1)
    {
        return cnoise(vec3(coord, time)) + time * 0.05;
    }
    if(type == 2)
    {
        float noise = 0.0;
        for(int i = 0; i < 8; i++)
        {
            noise += cnoise(vec3(coord / pow(2.0, float(i)), time)) / pow(2.0, float(i));
        }
        return noise;
    }
    if(type == 3)
    {
        return cnoise(vec3(coord, time)) + cos(coord.x / 2.5) + sin(coord.y / 2.5);
    }
    if(type == 4)
    {
        return pow(cnoise(vec3(coord, time)), 3.0) * 5.0;
    }
    if(type == 5)
    {
        float baseNoise = cnoise(vec3(coord / 10.0 + vec2(100.0, 100.0), 0));
        float landNoise = cnoise(vec3(coord, time));
        return baseNoise > 0.0 ? landNoise + 0.75 : landNoise - 0.5;
    }
    if(type == 6)
    {
        float timeNoise = 0.0 + cnoise(vec3(coord / 25.0 + vec2(100.0, 100.0), 0));
        return cnoise(vec3(coord, time * timeNoise));
    }
}

vec3 colorOnNoise(float noise)
{
    if(colorScheme == 0)
    {
        return vec3(1.0, 1.0, 1.5) * sin(noise);
    }
    if(colorScheme == 1)
    {
        return vec3(0.3, 0.0, 0.0) + vec3(1.25, 0.5, 0.5) * sin(noise);
    }
    if(colorScheme == 2)
    {
        return vec3(1.0, 2.0, 1.15) * sin(noise);
    }
    if(colorScheme == 3)
    {
        return vec3(sin(noise), sin(noise + 2.0), sin(noise + 4.0));
    }
    if(colorScheme == 4)
    {
        return vec3(sin(noise), sin(noise + 0.8), sin(noise + 1.6));
    }
    if(colorScheme == 5)
    {
        return vec3(mod(noise, 0.8), mod(noise * 1.3, 1.2), mod(noise * 0.9, 1.0));
    }
    if(colorScheme == 6)
    {
        return mod(noise, 1.0) > 0.5 ? vec3(1.0, 1.0, 1.0) : vec3(0.0, 0.0, 0.0);
    }
    if(colorScheme == 7)
    {
        vec3 baseColor = vec3(sin(noise), sin(noise * 1.1 + 2.0), sin(noise * 1.2 + 4.0));
        return mod(noise, 0.5) > 0.25 ? baseColor : vec3(1.0) - baseColor;
    }
    if(colorScheme == 8)
    {
        if(noise <= 0.0) return vec3(0, 0, clamp(noise + 1.0, 0.5, 1.0));
        if(noise <= 0.25) return vec3(1, 1, 0);
        if(noise <= 1.0) return vec3(0, 0.5 + mod(noise, 1.0), 0);
        if(noise <= 3.0) return vec3(1, 1, 1) * (0.25 + noise * 0.2);
        if(noise <= 6.0) return vec3(1, 1, 1);
    }
}

void main()
{
    vec2 coord = (gl_FragCoord.xy - resolution / 2.0) / resolution * camRange * vec2(resolution.x / resolution.y, 1.0) + camPos;
    //float noise = cnoise(vec3(coord.x, coord.y, time));
    float noise = noiseFromFormula(coord, formulaType);
    vec3 color = colorOnNoise(noise * colorSpeed);

    gl_FragColor = vec4(color, 1);
}
</script>

<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script src="Scripts/main.js"></script>

</body>

</html>
